<?php
/**
 * 简单的php上传类
 * Created by PhpStorm.
 * User: chenjichun
 * Date: 2021-03-28
 * Time: 22:25
 */

namespace Chenjichun;

class UploadFile
{

    const SUCCESS_CODE = 200;
    const ERROR_CODE   = 400;

    protected $config = [
        'maxSize'       => 20971520, //允许上传的文件大小, 默认20M
        'allowExts'     => ['jpg','jpeg','gif','png'],  //允许上传的后缀
        'isRename'      => true,    //文件是否重命名
        'field'         => 'file',  //上传前端name字段名称
        'savePath'      => './',    //文件保存路径
        'isResize'      => true,    //文件是否生成缩略图
        'resizeWidth'   => 200,     //缩略图宽度
        'resizeHeight'  => 200,     //缩略图高度
        'resizePer'     => 0,       //缩略比例
    ];

    public function __construct($data = [])
    {
        if (!empty($data)) {
            $this->config = array_merge($this->config, $data);
        }
    }

    public function __set($name,$value){
        if(isset($this->config[$name])) {
            $this->config[$name] = $value;
        }
        return true;
    }

    /** 文件上传
     * @param $file
     * @return array
     */
    public function upload($file)
    {

        $config  = $this->config;
        $fileArr = $file[$config['field']] ?? [];

        if (empty($fileArr)){
            return self::response(self::ERROR_CODE, '上传文件信息不能为空');
        }

        //文件大小检查
        if (!$this->checkSize($fileArr)){
            return self::response(self::ERROR_CODE,'文件大小超过了'. $config['maxSize'] / (1024*1024*1024) . 'MB');
        }

        //文件后缀检查
        $ext = $this->getFileExt($fileArr['name']);
        if (!$this->checkExt($ext)){
            return self::response(self::ERROR_CODE,'文件后缀不允许');
        }

        //是否重命名文件
        $saveName = pathinfo($fileArr['name'], PATHINFO_FILENAME );
        if ($config['isRename']){
            $saveName = $this->getRandomName();
        }

        //保存路径设置
        $savePath = rtrim($config['savePath'], '/'). '/';
        if (!is_dir($savePath)){
            self::mkdir($savePath);
        }

        $fileInfo = $savePath .  $saveName . '.' . $ext;
        if (!move_uploaded_file($fileArr['tmp_name'],  $fileInfo)) {
            return self::response(400, '上传文件失败');
        }

        $result = [
            'filename' => $saveName . '.'. $ext,
            'filepath' => $savePath,
            'fileFullPath' => $fileInfo,
            'filesize' => $fileArr['size'],
        ];

        //是否需要生成缩略图
        if ($config['isResize']){
            if (!self::hasGd()){
                @unlink($fileInfo);
                return self::response(self::ERROR_CODE,'请先安装GD库');
            }

            $resizeResult = $this->resize($fileInfo);
            if (self::ERROR_CODE == $resizeResult['code']){
                @unlink($fileInfo);
                return self::response(self::ERROR_CODE,'生成缩略图失败');
            }

            $result['resize'] = $resizeResult['data'];
        }

        return self::response(self::SUCCESS_CODE,'上传文件成功', $result);

    }

    /** 创建文件目录
     * @param $path
     */
    private static function mkdir($path)
    {
        mkdir($path, 0777, true);
        chmod($path, 0755);
    }

    /** 获取文件后缀
     * @param $filename
     * @return mixed
     */
    private static function getFileExt($filename)
    {
        return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    }

    /** 检查文件信息
     * @param $file array 文件信息
     * @return bool  true=ok; false=文件大于规定值
     */
    private function checkSize($file)
    {
        return $this->config['maxSize'] > $file['size'] ;
    }

    /** 后缀是否正常
     * @param string $ext 文件后缀 jpg|gif|jpeg|png
     * @return bool
     */
    private function checkExt($ext = '')
    {
        return in_array($ext, $this->config['allowExts']);
    }

    /** 获取随机文件名
     * @return string
     */
    private function getRandomName()
    {
        return md5(uniqid(mt_rand(10000, 99999), true));
    }


    /** 压缩图片
     * @param string $path 文件路径
     * @return array|false|string
     */
    public function resize($path)
    {

        if (!file_exists($path)){
            return self::response(self::ERROR_CODE, '图片不存在');
        }

        $imgInfo = file_get_contents($path);

        // 1 = gif，2 = jpg，3 = png
        // 获取图像信息
        list($bigWidth, $bigHight, $bigType) = getimagesizefromstring($imgInfo);

        $width  = $this->config['resizeWidth'];
        $height = $this->config['resizeHeight'];
        $per    = $this->config['resizePer'];

        // 缩放比例
        if ($per > 0) {
            $width  = $bigWidth * $per;
            $height = $bigHight * $per;
        }

        // 创建图画板
        $block = imagecreatetruecolor($width, $height);
        // 启用混色模式
        imagealphablending($block, false);
        // 保存PNG alpha通道信息
        imagesavealpha($block, true);
        // 创建原图画板
        $bigImg = imagecreatefromstring($imgInfo);

        // 缩放
        imagecopyresampled($block, $bigImg, 0, 0, 0, 0, $width, $height, $bigWidth, $bigHight);

        // 生成缩略图文件名
        $thumbName = 'thumb_' . basename($path);
        $tmpFilename = dirname($path) .'/' . $thumbName;

        switch ($bigType) {
            case 1:
                imagegif($block, $tmpFilename);
                break;
            case 2:
                imagejpeg($block, $tmpFilename);
                break;
            case 3:
                imagepng($block, $tmpFilename);
                break;
        }

        // 销毁
        imagedestroy($block);

        $result = [
            'filename'      => basename($tmpFilename),
            'filepath'      => dirname($tmpFilename),
            'fileFullPath'  => $tmpFilename,
            'filesize'      => filesize($tmpFilename)
        ];

        return self::response('ok',self::SUCCESS_CODE, $result);

    }

    /** GD库是否已安装
     * @return bool
     */
    private static function hasGd()
    {
        return function_exists('imagecreate');
    }

    /** 信息返回
     * @param int $code 200=成功;400=失败
     * @param string $msg 返回成功或错误信息
     * @param array $data 数据
     * @return array
     */
    private static function response($code = self::SUCCESS_CODE, $msg = '', $data = [])
    {
        return [
            'code' => $code,
            'msg'  => $msg,
            'data' => $data
        ];
    }

}

